1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.lang3.builder;
18
19 import java.lang.reflect.AccessibleObject;
20 import java.lang.reflect.Field;
21 import java.lang.reflect.Modifier;
22 import java.util.Collection;
23 import java.util.HashSet;
24 import java.util.Set;
25
26 import org.apache.commons.lang3.ArrayUtils;
27 import org.apache.commons.lang3.tuple.Pair;
28
29 /**
30 * <p>Assists in implementing {@link Object#equals(Object)} methods.</p>
31 *
32 * <p> This class provides methods to build a good equals method for any
33 * class. It follows rules laid out in
34 * <a href="http://www.oracle.com/technetwork/java/effectivejava-136174.html">Effective Java</a>
35 * , by Joshua Bloch. In particular the rule for comparing <code>doubles</code>,
36 * <code>floats</code>, and arrays can be tricky. Also, making sure that
37 * <code>equals()</code> and <code>hashCode()</code> are consistent can be
38 * difficult.</p>
39 *
40 * <p>Two Objects that compare as equals must generate the same hash code,
41 * but two Objects with the same hash code do not have to be equal.</p>
42 *
43 * <p>All relevant fields should be included in the calculation of equals.
44 * Derived fields may be ignored. In particular, any field used in
45 * generating a hash code must be used in the equals method, and vice
46 * versa.</p>
47 *
48 * <p>Typical use for the code is as follows:</p>
49 * <pre>
50 * public boolean equals(Object obj) {
51 * if (obj == null) { return false; }
52 * if (obj == this) { return true; }
53 * if (obj.getClass() != getClass()) {
54 * return false;
55 * }
56 * MyClass rhs = (MyClass) obj;
57 * return new EqualsBuilder()
58 * .appendSuper(super.equals(obj))
59 * .append(field1, rhs.field1)
60 * .append(field2, rhs.field2)
61 * .append(field3, rhs.field3)
62 * .isEquals();
63 * }
64 * </pre>
65 *
66 * <p> Alternatively, there is a method that uses reflection to determine
67 * the fields to test. Because these fields are usually private, the method,
68 * <code>reflectionEquals</code>, uses <code>AccessibleObject.setAccessible</code> to
69 * change the visibility of the fields. This will fail under a security
70 * manager, unless the appropriate permissions are set up correctly. It is
71 * also slower than testing explicitly. Non-primitive fields are compared using
72 * <code>equals()</code>.</p>
73 *
74 * <p> A typical invocation for this method would look like:</p>
75 * <pre>
76 * public boolean equals(Object obj) {
77 * return EqualsBuilder.reflectionEquals(this, obj);
78 * }
79 * </pre>
80 *
81 * @since 1.0
82 * @version $Id$
83 */
84 public class EqualsBuilder implements Builder<Boolean> {
85
86 /**
87 * <p>
88 * A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops.
89 * </p>
90 *
91 * @since 3.0
92 */
93 private static final ThreadLocal<Set<Pair<IDKey, IDKey>>> REGISTRY = new ThreadLocal<Set<Pair<IDKey, IDKey>>>();
94
95 /*
96 * NOTE: we cannot store the actual objects in a HashSet, as that would use the very hashCode()
97 * we are in the process of calculating.
98 *
99 * So we generate a one-to-one mapping from the original object to a new object.
100 *
101 * Now HashSet uses equals() to determine if two elements with the same hashcode really
102 * are equal, so we also need to ensure that the replacement objects are only equal
103 * if the original objects are identical.
104 *
105 * The original implementation (2.4 and before) used the System.indentityHashCode()
106 * method - however this is not guaranteed to generate unique ids (e.g. LANG-459)
107 *
108 * We now use the IDKey helper class (adapted from org.apache.axis.utils.IDKey)
109 * to disambiguate the duplicate ids.
110 */
111
112 /**
113 * <p>
114 * Returns the registry of object pairs being traversed by the reflection
115 * methods in the current thread.
116 * </p>
117 *
118 * @return Set the registry of objects being traversed
119 * @since 3.0
120 */
121 static Set<Pair<IDKey, IDKey>> getRegistry() {
122 return REGISTRY.get();
123 }
124
125 /**
126 * <p>
127 * Converters value pair into a register pair.
128 * </p>
129 *
130 * @param lhs <code>this</code> object
131 * @param rhs the other object
132 *
133 * @return the pair
134 */
135 static Pair<IDKey, IDKey> getRegisterPair(final Object lhs, final Object rhs) {
136 final IDKey left = new IDKey(lhs);
137 final IDKey right = new IDKey(rhs);
138 return Pair.of(left, right);
139 }
140
141 /**
142 * <p>
143 * Returns <code>true</code> if the registry contains the given object pair.
144 * Used by the reflection methods to avoid infinite loops.
145 * Objects might be swapped therefore a check is needed if the object pair
146 * is registered in given or swapped order.
147 * </p>
148 *
149 * @param lhs <code>this</code> object to lookup in registry
150 * @param rhs the other object to lookup on registry
151 * @return boolean <code>true</code> if the registry contains the given object.
152 * @since 3.0
153 */
154 static boolean isRegistered(final Object lhs, final Object rhs) {
155 final Set<Pair<IDKey, IDKey>> registry = getRegistry();
156 final Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
157 final Pair<IDKey, IDKey> swappedPair = Pair.of(pair.getLeft(), pair.getRight());
158
159 return registry != null
160 && (registry.contains(pair) || registry.contains(swappedPair));
161 }
162
163 /**
164 * <p>
165 * Registers the given object pair.
166 * Used by the reflection methods to avoid infinite loops.
167 * </p>
168 *
169 * @param lhs <code>this</code> object to register
170 * @param rhs the other object to register
171 */
172 static void register(final Object lhs, final Object rhs) {
173 synchronized (EqualsBuilder.class) {
174 if (getRegistry() == null) {
175 REGISTRY.set(new HashSet<Pair<IDKey, IDKey>>());
176 }
177 }
178
179 final Set<Pair<IDKey, IDKey>> registry = getRegistry();
180 final Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
181 registry.add(pair);
182 }
183
184 /**
185 * <p>
186 * Unregisters the given object pair.
187 * </p>
188 *
189 * <p>
190 * Used by the reflection methods to avoid infinite loops.
191 *
192 * @param lhs <code>this</code> object to unregister
193 * @param rhs the other object to unregister
194 * @since 3.0
195 */
196 static void unregister(final Object lhs, final Object rhs) {
197 Set<Pair<IDKey, IDKey>> registry = getRegistry();
198 if (registry != null) {
199 final Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
200 registry.remove(pair);
201 synchronized (EqualsBuilder.class) {
202 //read again
203 registry = getRegistry();
204 if (registry != null && registry.isEmpty()) {
205 REGISTRY.remove();
206 }
207 }
208 }
209 }
210
211 /**
212 * If the fields tested are equals.
213 * The default value is <code>true</code>.
214 */
215 private boolean isEquals = true;
216
217 /**
218 * <p>Constructor for EqualsBuilder.</p>
219 *
220 * <p>Starts off assuming that equals is <code>true</code>.</p>
221 * @see Object#equals(Object)
222 */
223 public EqualsBuilder() {
224 // do nothing for now.
225 }
226
227 //-------------------------------------------------------------------------
228
229 /**
230 * <p>This method uses reflection to determine if the two <code>Object</code>s
231 * are equal.</p>
232 *
233 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
234 * fields. This means that it will throw a security exception if run under
235 * a security manager, if the permissions are not set up correctly. It is also
236 * not as efficient as testing explicitly. Non-primitive fields are compared using
237 * <code>equals()</code>.</p>
238 *
239 * <p>Transient members will be not be tested, as they are likely derived
240 * fields, and not part of the value of the Object.</p>
241 *
242 * <p>Static fields will not be tested. Superclass fields will be included.</p>
243 *
244 * @param lhs <code>this</code> object
245 * @param rhs the other object
246 * @param excludeFields Collection of String field names to exclude from testing
247 * @return <code>true</code> if the two Objects have tested equals.
248 */
249 public static boolean reflectionEquals(final Object lhs, final Object rhs, final Collection<String> excludeFields) {
250 return reflectionEquals(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields));
251 }
252
253 /**
254 * <p>This method uses reflection to determine if the two <code>Object</code>s
255 * are equal.</p>
256 *
257 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
258 * fields. This means that it will throw a security exception if run under
259 * a security manager, if the permissions are not set up correctly. It is also
260 * not as efficient as testing explicitly. Non-primitive fields are compared using
261 * <code>equals()</code>.</p>
262 *
263 * <p>Transient members will be not be tested, as they are likely derived
264 * fields, and not part of the value of the Object.</p>
265 *
266 * <p>Static fields will not be tested. Superclass fields will be included.</p>
267 *
268 * @param lhs <code>this</code> object
269 * @param rhs the other object
270 * @param excludeFields array of field names to exclude from testing
271 * @return <code>true</code> if the two Objects have tested equals.
272 */
273 public static boolean reflectionEquals(final Object lhs, final Object rhs, final String... excludeFields) {
274 return reflectionEquals(lhs, rhs, false, null, excludeFields);
275 }
276
277 /**
278 * <p>This method uses reflection to determine if the two <code>Object</code>s
279 * are equal.</p>
280 *
281 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
282 * fields. This means that it will throw a security exception if run under
283 * a security manager, if the permissions are not set up correctly. It is also
284 * not as efficient as testing explicitly. Non-primitive fields are compared using
285 * <code>equals()</code>.</p>
286 *
287 * <p>If the TestTransients parameter is set to <code>true</code>, transient
288 * members will be tested, otherwise they are ignored, as they are likely
289 * derived fields, and not part of the value of the <code>Object</code>.</p>
290 *
291 * <p>Static fields will not be tested. Superclass fields will be included.</p>
292 *
293 * @param lhs <code>this</code> object
294 * @param rhs the other object
295 * @param testTransients whether to include transient fields
296 * @return <code>true</code> if the two Objects have tested equals.
297 */
298 public static boolean reflectionEquals(final Object lhs, final Object rhs, final boolean testTransients) {
299 return reflectionEquals(lhs, rhs, testTransients, null);
300 }
301
302 /**
303 * <p>This method uses reflection to determine if the two <code>Object</code>s
304 * are equal.</p>
305 *
306 * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
307 * fields. This means that it will throw a security exception if run under
308 * a security manager, if the permissions are not set up correctly. It is also
309 * not as efficient as testing explicitly. Non-primitive fields are compared using
310 * <code>equals()</code>.</p>
311 *
312 * <p>If the testTransients parameter is set to <code>true</code>, transient
313 * members will be tested, otherwise they are ignored, as they are likely
314 * derived fields, and not part of the value of the <code>Object</code>.</p>
315 *
316 * <p>Static fields will not be included. Superclass fields will be appended
317 * up to and including the specified superclass. A null superclass is treated
318 * as java.lang.Object.</p>
319 *
320 * @param lhs <code>this</code> object
321 * @param rhs the other object
322 * @param testTransients whether to include transient fields
323 * @param reflectUpToClass the superclass to reflect up to (inclusive),
324 * may be <code>null</code>
325 * @param excludeFields array of field names to exclude from testing
326 * @return <code>true</code> if the two Objects have tested equals.
327 * @since 2.0
328 */
329 public static boolean reflectionEquals(final Object lhs, final Object rhs, final boolean testTransients, final Class<?> reflectUpToClass,
330 final String... excludeFields) {
331 if (lhs == rhs) {
332 return true;
333 }
334 if (lhs == null || rhs == null) {
335 return false;
336 }
337 // Find the leaf class since there may be transients in the leaf
338 // class or in classes between the leaf and root.
339 // If we are not testing transients or a subclass has no ivars,
340 // then a subclass can test equals to a superclass.
341 final Class<?> lhsClass = lhs.getClass();
342 final Class<?> rhsClass = rhs.getClass();
343 Class<?> testClass;
344 if (lhsClass.isInstance(rhs)) {
345 testClass = lhsClass;
346 if (!rhsClass.isInstance(lhs)) {
347 // rhsClass is a subclass of lhsClass
348 testClass = rhsClass;
349 }
350 } else if (rhsClass.isInstance(lhs)) {
351 testClass = rhsClass;
352 if (!lhsClass.isInstance(rhs)) {
353 // lhsClass is a subclass of rhsClass
354 testClass = lhsClass;
355 }
356 } else {
357 // The two classes are not related.
358 return false;
359 }
360 final EqualsBuilder equalsBuilder = new EqualsBuilder();
361 try {
362 if (testClass.isArray()) {
363 equalsBuilder.append(lhs, rhs);
364 } else {
365 reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
366 while (testClass.getSuperclass() != null && testClass != reflectUpToClass) {
367 testClass = testClass.getSuperclass();
368 reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
369 }
370 }
371 } catch (final IllegalArgumentException e) {
372 // In this case, we tried to test a subclass vs. a superclass and
373 // the subclass has ivars or the ivars are transient and
374 // we are testing transients.
375 // If a subclass has ivars that we are trying to test them, we get an
376 // exception and we know that the objects are not equal.
377 return false;
378 }
379 return equalsBuilder.isEquals();
380 }
381
382 /**
383 * <p>Appends the fields and values defined by the given object of the
384 * given Class.</p>
385 *
386 * @param lhs the left hand object
387 * @param rhs the right hand object
388 * @param clazz the class to append details of
389 * @param builder the builder to append to
390 * @param useTransients whether to test transient fields
391 * @param excludeFields array of field names to exclude from testing
392 */
393 private static void reflectionAppend(
394 final Object lhs,
395 final Object rhs,
396 final Class<?> clazz,
397 final EqualsBuilder builder,
398 final boolean useTransients,
399 final String[] excludeFields) {
400
401 if (isRegistered(lhs, rhs)) {
402 return;
403 }
404
405 try {
406 register(lhs, rhs);
407 final Field[] fields = clazz.getDeclaredFields();
408 AccessibleObject.setAccessible(fields, true);
409 for (int i = 0; i < fields.length && builder.isEquals; i++) {
410 final Field f = fields[i];
411 if (!ArrayUtils.contains(excludeFields, f.getName())
412 && (f.getName().indexOf('$') == -1)
413 && (useTransients || !Modifier.isTransient(f.getModifiers()))
414 && (!Modifier.isStatic(f.getModifiers()))) {
415 try {
416 builder.append(f.get(lhs), f.get(rhs));
417 } catch (final IllegalAccessException e) {
418 //this can't happen. Would get a Security exception instead
419 //throw a runtime exception in case the impossible happens.
420 throw new InternalError("Unexpected IllegalAccessException");
421 }
422 }
423 }
424 } finally {
425 unregister(lhs, rhs);
426 }
427 }
428
429 //-------------------------------------------------------------------------
430
431 /**
432 * <p>Adds the result of <code>super.equals()</code> to this builder.</p>
433 *
434 * @param superEquals the result of calling <code>super.equals()</code>
435 * @return EqualsBuilder - used to chain calls.
436 * @since 2.0
437 */
438 public EqualsBuilder appendSuper(final boolean superEquals) {
439 if (isEquals == false) {
440 return this;
441 }
442 isEquals = superEquals;
443 return this;
444 }
445
446 //-------------------------------------------------------------------------
447
448 /**
449 * <p>Test if two <code>Object</code>s are equal using their
450 * <code>equals</code> method.</p>
451 *
452 * @param lhs the left hand object
453 * @param rhs the right hand object
454 * @return EqualsBuilder - used to chain calls.
455 */
456 public EqualsBuilder append(final Object lhs, final Object rhs) {
457 if (isEquals == false) {
458 return this;
459 }
460 if (lhs == rhs) {
461 return this;
462 }
463 if (lhs == null || rhs == null) {
464 this.setEquals(false);
465 return this;
466 }
467 final Class<?> lhsClass = lhs.getClass();
468 if (!lhsClass.isArray()) {
469 // The simple case, not an array, just test the element
470 isEquals = lhs.equals(rhs);
471 } else if (lhs.getClass() != rhs.getClass()) {
472 // Here when we compare different dimensions, for example: a boolean[][] to a boolean[]
473 this.setEquals(false);
474 }
475 // 'Switch' on type of array, to dispatch to the correct handler
476 // This handles multi dimensional arrays of the same depth
477 else if (lhs instanceof long[]) {
478 append((long[]) lhs, (long[]) rhs);
479 } else if (lhs instanceof int[]) {
480 append((int[]) lhs, (int[]) rhs);
481 } else if (lhs instanceof short[]) {
482 append((short[]) lhs, (short[]) rhs);
483 } else if (lhs instanceof char[]) {
484 append((char[]) lhs, (char[]) rhs);
485 } else if (lhs instanceof byte[]) {
486 append((byte[]) lhs, (byte[]) rhs);
487 } else if (lhs instanceof double[]) {
488 append((double[]) lhs, (double[]) rhs);
489 } else if (lhs instanceof float[]) {
490 append((float[]) lhs, (float[]) rhs);
491 } else if (lhs instanceof boolean[]) {
492 append((boolean[]) lhs, (boolean[]) rhs);
493 } else {
494 // Not an array of primitives
495 append((Object[]) lhs, (Object[]) rhs);
496 }
497 return this;
498 }
499
500 /**
501 * <p>
502 * Test if two <code>long</code> s are equal.
503 * </p>
504 *
505 * @param lhs
506 * the left hand <code>long</code>
507 * @param rhs
508 * the right hand <code>long</code>
509 * @return EqualsBuilder - used to chain calls.
510 */
511 public EqualsBuilder append(final long lhs, final long rhs) {
512 if (isEquals == false) {
513 return this;
514 }
515 isEquals = (lhs == rhs);
516 return this;
517 }
518
519 /**
520 * <p>Test if two <code>int</code>s are equal.</p>
521 *
522 * @param lhs the left hand <code>int</code>
523 * @param rhs the right hand <code>int</code>
524 * @return EqualsBuilder - used to chain calls.
525 */
526 public EqualsBuilder append(final int lhs, final int rhs) {
527 if (isEquals == false) {
528 return this;
529 }
530 isEquals = (lhs == rhs);
531 return this;
532 }
533
534 /**
535 * <p>Test if two <code>short</code>s are equal.</p>
536 *
537 * @param lhs the left hand <code>short</code>
538 * @param rhs the right hand <code>short</code>
539 * @return EqualsBuilder - used to chain calls.
540 */
541 public EqualsBuilder append(final short lhs, final short rhs) {
542 if (isEquals == false) {
543 return this;
544 }
545 isEquals = (lhs == rhs);
546 return this;
547 }
548
549 /**
550 * <p>Test if two <code>char</code>s are equal.</p>
551 *
552 * @param lhs the left hand <code>char</code>
553 * @param rhs the right hand <code>char</code>
554 * @return EqualsBuilder - used to chain calls.
555 */
556 public EqualsBuilder append(final char lhs, final char rhs) {
557 if (isEquals == false) {
558 return this;
559 }
560 isEquals = (lhs == rhs);
561 return this;
562 }
563
564 /**
565 * <p>Test if two <code>byte</code>s are equal.</p>
566 *
567 * @param lhs the left hand <code>byte</code>
568 * @param rhs the right hand <code>byte</code>
569 * @return EqualsBuilder - used to chain calls.
570 */
571 public EqualsBuilder append(final byte lhs, final byte rhs) {
572 if (isEquals == false) {
573 return this;
574 }
575 isEquals = (lhs == rhs);
576 return this;
577 }
578
579 /**
580 * <p>Test if two <code>double</code>s are equal by testing that the
581 * pattern of bits returned by <code>doubleToLong</code> are equal.</p>
582 *
583 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
584 *
585 * <p>It is compatible with the hash code generated by
586 * <code>HashCodeBuilder</code>.</p>
587 *
588 * @param lhs the left hand <code>double</code>
589 * @param rhs the right hand <code>double</code>
590 * @return EqualsBuilder - used to chain calls.
591 */
592 public EqualsBuilder append(final double lhs, final double rhs) {
593 if (isEquals == false) {
594 return this;
595 }
596 return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs));
597 }
598
599 /**
600 * <p>Test if two <code>float</code>s are equal byt testing that the
601 * pattern of bits returned by doubleToLong are equal.</p>
602 *
603 * <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
604 *
605 * <p>It is compatible with the hash code generated by
606 * <code>HashCodeBuilder</code>.</p>
607 *
608 * @param lhs the left hand <code>float</code>
609 * @param rhs the right hand <code>float</code>
610 * @return EqualsBuilder - used to chain calls.
611 */
612 public EqualsBuilder append(final float lhs, final float rhs) {
613 if (isEquals == false) {
614 return this;
615 }
616 return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs));
617 }
618
619 /**
620 * <p>Test if two <code>booleans</code>s are equal.</p>
621 *
622 * @param lhs the left hand <code>boolean</code>
623 * @param rhs the right hand <code>boolean</code>
624 * @return EqualsBuilder - used to chain calls.
625 */
626 public EqualsBuilder append(final boolean lhs, final boolean rhs) {
627 if (isEquals == false) {
628 return this;
629 }
630 isEquals = (lhs == rhs);
631 return this;
632 }
633
634 /**
635 * <p>Performs a deep comparison of two <code>Object</code> arrays.</p>
636 *
637 * <p>This also will be called for the top level of
638 * multi-dimensional, ragged, and multi-typed arrays.</p>
639 *
640 * @param lhs the left hand <code>Object[]</code>
641 * @param rhs the right hand <code>Object[]</code>
642 * @return EqualsBuilder - used to chain calls.
643 */
644 public EqualsBuilder append(final Object[] lhs, final Object[] rhs) {
645 if (isEquals == false) {
646 return this;
647 }
648 if (lhs == rhs) {
649 return this;
650 }
651 if (lhs == null || rhs == null) {
652 this.setEquals(false);
653 return this;
654 }
655 if (lhs.length != rhs.length) {
656 this.setEquals(false);
657 return this;
658 }
659 for (int i = 0; i < lhs.length && isEquals; ++i) {
660 append(lhs[i], rhs[i]);
661 }
662 return this;
663 }
664
665 /**
666 * <p>Deep comparison of array of <code>long</code>. Length and all
667 * values are compared.</p>
668 *
669 * <p>The method {@link #append(long, long)} is used.</p>
670 *
671 * @param lhs the left hand <code>long[]</code>
672 * @param rhs the right hand <code>long[]</code>
673 * @return EqualsBuilder - used to chain calls.
674 */
675 public EqualsBuilder append(final long[] lhs, final long[] rhs) {
676 if (isEquals == false) {
677 return this;
678 }
679 if (lhs == rhs) {
680 return this;
681 }
682 if (lhs == null || rhs == null) {
683 this.setEquals(false);
684 return this;
685 }
686 if (lhs.length != rhs.length) {
687 this.setEquals(false);
688 return this;
689 }
690 for (int i = 0; i < lhs.length && isEquals; ++i) {
691 append(lhs[i], rhs[i]);
692 }
693 return this;
694 }
695
696 /**
697 * <p>Deep comparison of array of <code>int</code>. Length and all
698 * values are compared.</p>
699 *
700 * <p>The method {@link #append(int, int)} is used.</p>
701 *
702 * @param lhs the left hand <code>int[]</code>
703 * @param rhs the right hand <code>int[]</code>
704 * @return EqualsBuilder - used to chain calls.
705 */
706 public EqualsBuilder append(final int[] lhs, final int[] rhs) {
707 if (isEquals == false) {
708 return this;
709 }
710 if (lhs == rhs) {
711 return this;
712 }
713 if (lhs == null || rhs == null) {
714 this.setEquals(false);
715 return this;
716 }
717 if (lhs.length != rhs.length) {
718 this.setEquals(false);
719 return this;
720 }
721 for (int i = 0; i < lhs.length && isEquals; ++i) {
722 append(lhs[i], rhs[i]);
723 }
724 return this;
725 }
726
727 /**
728 * <p>Deep comparison of array of <code>short</code>. Length and all
729 * values are compared.</p>
730 *
731 * <p>The method {@link #append(short, short)} is used.</p>
732 *
733 * @param lhs the left hand <code>short[]</code>
734 * @param rhs the right hand <code>short[]</code>
735 * @return EqualsBuilder - used to chain calls.
736 */
737 public EqualsBuilder append(final short[] lhs, final short[] rhs) {
738 if (isEquals == false) {
739 return this;
740 }
741 if (lhs == rhs) {
742 return this;
743 }
744 if (lhs == null || rhs == null) {
745 this.setEquals(false);
746 return this;
747 }
748 if (lhs.length != rhs.length) {
749 this.setEquals(false);
750 return this;
751 }
752 for (int i = 0; i < lhs.length && isEquals; ++i) {
753 append(lhs[i], rhs[i]);
754 }
755 return this;
756 }
757
758 /**
759 * <p>Deep comparison of array of <code>char</code>. Length and all
760 * values are compared.</p>
761 *
762 * <p>The method {@link #append(char, char)} is used.</p>
763 *
764 * @param lhs the left hand <code>char[]</code>
765 * @param rhs the right hand <code>char[]</code>
766 * @return EqualsBuilder - used to chain calls.
767 */
768 public EqualsBuilder append(final char[] lhs, final char[] rhs) {
769 if (isEquals == false) {
770 return this;
771 }
772 if (lhs == rhs) {
773 return this;
774 }
775 if (lhs == null || rhs == null) {
776 this.setEquals(false);
777 return this;
778 }
779 if (lhs.length != rhs.length) {
780 this.setEquals(false);
781 return this;
782 }
783 for (int i = 0; i < lhs.length && isEquals; ++i) {
784 append(lhs[i], rhs[i]);
785 }
786 return this;
787 }
788
789 /**
790 * <p>Deep comparison of array of <code>byte</code>. Length and all
791 * values are compared.</p>
792 *
793 * <p>The method {@link #append(byte, byte)} is used.</p>
794 *
795 * @param lhs the left hand <code>byte[]</code>
796 * @param rhs the right hand <code>byte[]</code>
797 * @return EqualsBuilder - used to chain calls.
798 */
799 public EqualsBuilder append(final byte[] lhs, final byte[] rhs) {
800 if (isEquals == false) {
801 return this;
802 }
803 if (lhs == rhs) {
804 return this;
805 }
806 if (lhs == null || rhs == null) {
807 this.setEquals(false);
808 return this;
809 }
810 if (lhs.length != rhs.length) {
811 this.setEquals(false);
812 return this;
813 }
814 for (int i = 0; i < lhs.length && isEquals; ++i) {
815 append(lhs[i], rhs[i]);
816 }
817 return this;
818 }
819
820 /**
821 * <p>Deep comparison of array of <code>double</code>. Length and all
822 * values are compared.</p>
823 *
824 * <p>The method {@link #append(double, double)} is used.</p>
825 *
826 * @param lhs the left hand <code>double[]</code>
827 * @param rhs the right hand <code>double[]</code>
828 * @return EqualsBuilder - used to chain calls.
829 */
830 public EqualsBuilder append(final double[] lhs, final double[] rhs) {
831 if (isEquals == false) {
832 return this;
833 }
834 if (lhs == rhs) {
835 return this;
836 }
837 if (lhs == null || rhs == null) {
838 this.setEquals(false);
839 return this;
840 }
841 if (lhs.length != rhs.length) {
842 this.setEquals(false);
843 return this;
844 }
845 for (int i = 0; i < lhs.length && isEquals; ++i) {
846 append(lhs[i], rhs[i]);
847 }
848 return this;
849 }
850
851 /**
852 * <p>Deep comparison of array of <code>float</code>. Length and all
853 * values are compared.</p>
854 *
855 * <p>The method {@link #append(float, float)} is used.</p>
856 *
857 * @param lhs the left hand <code>float[]</code>
858 * @param rhs the right hand <code>float[]</code>
859 * @return EqualsBuilder - used to chain calls.
860 */
861 public EqualsBuilder append(final float[] lhs, final float[] rhs) {
862 if (isEquals == false) {
863 return this;
864 }
865 if (lhs == rhs) {
866 return this;
867 }
868 if (lhs == null || rhs == null) {
869 this.setEquals(false);
870 return this;
871 }
872 if (lhs.length != rhs.length) {
873 this.setEquals(false);
874 return this;
875 }
876 for (int i = 0; i < lhs.length && isEquals; ++i) {
877 append(lhs[i], rhs[i]);
878 }
879 return this;
880 }
881
882 /**
883 * <p>Deep comparison of array of <code>boolean</code>. Length and all
884 * values are compared.</p>
885 *
886 * <p>The method {@link #append(boolean, boolean)} is used.</p>
887 *
888 * @param lhs the left hand <code>boolean[]</code>
889 * @param rhs the right hand <code>boolean[]</code>
890 * @return EqualsBuilder - used to chain calls.
891 */
892 public EqualsBuilder append(final boolean[] lhs, final boolean[] rhs) {
893 if (isEquals == false) {
894 return this;
895 }
896 if (lhs == rhs) {
897 return this;
898 }
899 if (lhs == null || rhs == null) {
900 this.setEquals(false);
901 return this;
902 }
903 if (lhs.length != rhs.length) {
904 this.setEquals(false);
905 return this;
906 }
907 for (int i = 0; i < lhs.length && isEquals; ++i) {
908 append(lhs[i], rhs[i]);
909 }
910 return this;
911 }
912
913 /**
914 * <p>Returns <code>true</code> if the fields that have been checked
915 * are all equal.</p>
916 *
917 * @return boolean
918 */
919 public boolean isEquals() {
920 return this.isEquals;
921 }
922
923 /**
924 * <p>Returns <code>true</code> if the fields that have been checked
925 * are all equal.</p>
926 *
927 * @return <code>true</code> if all of the fields that have been checked
928 * are equal, <code>false</code> otherwise.
929 *
930 * @since 3.0
931 */
932 @Override
933 public Boolean build() {
934 return Boolean.valueOf(isEquals());
935 }
936
937 /**
938 * Sets the <code>isEquals</code> value.
939 *
940 * @param isEquals The value to set.
941 * @since 2.1
942 */
943 protected void setEquals(final boolean isEquals) {
944 this.isEquals = isEquals;
945 }
946
947 /**
948 * Reset the EqualsBuilder so you can use the same object again
949 * @since 2.5
950 */
951 public void reset() {
952 this.isEquals = true;
953 }
954 }